package com.cjm.one.security.fillter;




import com.cjm.one.common.constant.RedisConstants;
import com.cjm.one.common.result.Result;
import com.cjm.one.common.result.ResultCodeEnum;
import com.cjm.one.common.utils.AuthSysUserContextHolder;
import com.cjm.one.common.utils.JSONUtils;
import com.cjm.one.common.utils.ResponseUtil;
import com.cjm.one.model.system.entity.SysUserInfo;
import com.cjm.one.security.config.PermissionPathPropertis;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 身份验证过滤器
 * </p>
 */
@Slf4j
@DependsOn("permissionPathPropertis")
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private RedisTemplate redisTemplate;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    private  PermissionPathPropertis permissionPathPropertis ;


    public TokenAuthenticationFilter(RedisTemplate redisTemplate, PermissionPathPropertis permissionPathPropertis) {
        this.redisTemplate = redisTemplate;
        this.permissionPathPropertis = permissionPathPropertis;

    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        //如果排除的接口列表的直接放行
        String uri = request.getRequestURI();
        log.info("admin请求的路径uri:"+uri);
        log.info("请求方式：{}",request.getMethod());
        log.info("Query参数：{}",request.getQueryString());
//        log.info("Body参数：{}",request.getReader().lines().collect(Collectors.joining(System.lineSeparator())));
        for (String url : permissionPathPropertis.getIgnoreUrlList()) {
            if(antPathMatcher.match(url, uri)) {
                log.info("放行:"+uri);
                chain.doFilter(request, response);
                return;
            }
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(request,response);
        if(null != authentication) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } else {
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.PERMISSION));
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request,HttpServletResponse response) throws JsonProcessingException {
        // token置于header里
        String token = request.getHeader("authorization");
        log.info("token:"+token);
        if (StringUtils.hasText(token)) {
            String  str = (String)redisTemplate.opsForValue().get(RedisConstants.SYS_USER_LOGIN_KEY_TOKEN + token);
            if (!StringUtils.hasText(str)) {
                ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_AUTH));
                return null;
            }
            log.info("str:"+str);
            SysUserInfo sysUserInfo = JSONUtils.toBean(str, SysUserInfo.class);

            // TODO:待优化 从redis中获取权限列表
            log.info("得到的sysUserInfo:"+sysUserInfo);
            if (null != sysUserInfo) {
                //设置id
                //TODO 需要判断当app端登陆时，需要将判断
                AuthSysUserContextHolder.setAuthContextSysUser(sysUserInfo);

                if (null != sysUserInfo.getUserPermsList() && sysUserInfo.getUserPermsList().size() > 0) {
                    List<SimpleGrantedAuthority> authorities = sysUserInfo.getUserPermsList()
                            .stream()
                            .filter(code -> StringUtils.hasText(code.trim()))
                            .map(code -> new SimpleGrantedAuthority(code.trim()))
                            .collect(Collectors.toList());
                    log.info("authorities:"+ JSONUtils.toString(authorities));
                    return new UsernamePasswordAuthenticationToken(sysUserInfo.getUsername(), null, authorities);
                } else {
                    return new UsernamePasswordAuthenticationToken(sysUserInfo.getUsername(), null, new ArrayList<>());
                }
            }
        }
        return null;
    }
}
